import logging
import os
import sys
from hashlib import md5
from ftplib import FTP, FTP_TLS
from pyftpdlib.authorizers import DummyAuthorizer, AuthenticationFailed
from pyftpdlib.handlers import FTPHandler, ThrottledDTPHandler, TLS_FTPHandler
from pyftpdlib.servers import FTPServer, ThreadedFTPServer
from threading import Thread

logging.basicConfig(filename='./ftp.log', level=logging.INFO)


class DummyMD5Authorizer(DummyAuthorizer):

    def validate_authentication(self, username, password, handler):
        if sys.version_info >= (3, 0):
            password = md5(password.encode('latin1'))
        hash_ = md5(password).hexdigest()
        try:
            if self.user_table[username]['pwd'] != hash_:
                raise KeyError
        except KeyError:
            raise AuthenticationFailed


def ftp_server():
    authorizer = DummyAuthorizer()
    authorizer.add_user('user', '12345', '.', perm='elradfmwMT')
    authorizer.add_anonymous(os.getcwd())

    dtp_handler = ThrottledDTPHandler
    dtp_handler.read_limit = 30720  # 30 Kb/sec (30 * 1024)
    dtp_handler.write_limit = 30720  # 30 Kb/sec (30 * 1024)

    ftp_address = ('0.0.0.0', 21)
    ftp_handler = FTPHandler
    ftp_handler.banner = 'hi'
    ftp_handler.authorizer = authorizer
    ftp_handler.permit_foreign_addresses = True
    ftp_handler.dtp_handler = dtp_handler
    ftp_handler.log_prefix = 'ftp- [%(username)s]@%(remote_ip)s'
    ftp_handler.masquerade_address = '151.25.42.11'
    ftp_handler.passive_ports = range(60000, 65535)

    ftp_server = ThreadedFTPServer(ftp_address, ftp_handler)
    ftp_server.max_cons = 256
    ftp_server.max_cons_per_ip = 5
    ftp_server.serve_forever()


def sftp_server():
    authorizer = DummyAuthorizer()
    authorizer.add_user('user', '12345', '.', perm='elradfmwMT')
    authorizer.add_anonymous(os.getcwd())

    dtp_handler = ThrottledDTPHandler
    dtp_handler.read_limit = 30720  # 30 Kb/sec (30 * 1024)
    dtp_handler.write_limit = 30720  # 30 Kb/sec (30 * 1024)

    sftp_address = ('0.0.0.0', 21)
    sftp_handler = TLS_FTPHandler
    sftp_handler.banner = 'hi'
    sftp_handler.authorizer = authorizer
    sftp_handler.permit_foreign_addresses = True
    sftp_handler.dtp_handler = dtp_handler
    sftp_handler.log_prefix = 'sftp- [%(username)s]@%(remote_ip)s'
    sftp_handler.masquerade_address = '151.25.42.11'
    sftp_handler.passive_ports = range(60000, 65535)
    # ssl加密
    # 导入private key + certification的pem文件(上半截是私钥,下半截是证书)
    # sftp_handler.certfile = 'keycert.pem'
    sftp_handler.certfile = 'server.crt'
    sftp_handler.keyfile = 'server.key'
    # requires SSL for both control and data channel 启用ssl加密传输
    sftp_handler.tls_control_required = False  # 控制连接启用ssl加密
    # 我个人的感觉是,如果是开了这个控制连接加密,那么FTP刷新或者打开目录时经常要卡顿,卡的时间稳定在21秒左右,提示的是[正在协商密码],如果把这个控制连接加密关掉,速度就快多了.
    sftp_handler.tls_data_required = False  # 数据连接启用ssl加密

    sftp_server = ThreadedFTPServer(sftp_address, sftp_handler)
    sftp_server.max_cons = 256
    sftp_server.max_cons_per_ip = 5
    sftp_server.serve_forever()


def ftp_client():
    host = '127.0.0.1'
    port = 21
    user = 'user'
    password = '12345'
    try:
        with FTP() as ftp:
            ftp.connect(host=host, port=port)
            print(ftp.login(user=user, passwd=password))
            print(ftp.getwelcome())
            # 如果 val 为 true，则打开“被动”模式，否则禁用被动模式。 默认下被动模式是打开的。
            ftp.set_pasv(False)
            print(ftp.dir())
    except Exception as e:
        print(e)


def sftp_client():
    host = '127.0.0.1'
    port = 22
    user = 'user'
    password = '12345'
    keyfile = 'server.key'
    certfile = 'server.crt'

    try:
        with FTP_TLS(keyfile=keyfile, certfile=certfile) as sftp:
            sftp.connect(host=host, port=port)
            print(sftp.login(user=user, passwd=password))
            print(sftp.getwelcome())
            # 如果 val 为 true，则打开“被动”模式，否则禁用被动模式。 默认下被动模式是打开的。
            sftp.set_pasv(False)
            print(sftp.dir())
    except Exception as e:
        print(e)


def main():
    password = '12345'
    hash_ = md5(password.encode('latin1')).hexdigest()
    authorizer = DummyMD5Authorizer()
    authorizer.add_user('user', hash_, os.getcwd(), perm='elradfmwMT')
    authorizer.add_anonymous(os.getcwd())
    handler = FTPHandler
    handler.authorizer = authorizer
    server = FTPServer(('0.0.0.0', 21), handler)
    server.serve_forever()


if __name__ == '__main__':
    # t1 = Thread(target=sftp_server)
    # t1.start()
    # t2 = Thread(target=ftp_client)
    # t2.start()
    # ftp_server()
    # sftp_server()
    # ftp_client()
    # sftp_client()
    pass
